package com.gydz.gydzbaseframeworkboot.SystemControl.utils;

import java.lang.reflect.Method;
import java.security.Principal;
import java.util.Date;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import com.gydz.gydzbaseframeworkboot.SystemControl.dao.OperationLogMapper;
import com.gydz.gydzbaseframeworkboot.SystemControl.domain.OperationLog;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Component
@Aspect
public class SystemOperLogs {

    @Resource
    private OperationLogMapper operLogMapper;

    //声明AOP切入点
    @Pointcut("@annotation(com.gydz.gydzbaseframeworkboot.SystemControl.utils.Log)")
    public void log() {}

    @After("log()")
    public void after(JoinPoint point) throws Throwable {
        Log Log = getMethodRemark(point);
        if (Log != null) {
            HttpServletRequest request = this.getRequest(point);
            this.insertLog(request, Log);
        }
    }


    /**
     * 获取方法的中文备注____用于记录用户的操作日志描述
     *
     * @param joinPoint
     * @return
     * @throws Exception
     */
    @SuppressWarnings("rawtypes")
    private Log getMethodRemark(JoinPoint joinPoint) throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();

        Class targetClass = Class.forName(targetName);
        Method[] method = targetClass.getMethods();
        for (Method m : method) {
            if (m.getName().equals(methodName)) {
                Class[] tmpCs = m.getParameterTypes();
                if (tmpCs.length == arguments.length) {
                    Log methodCache = m.getAnnotation(Log.class);
                    if (methodCache != null && !("").equals(methodCache.remark())) {
                        return methodCache;
                    }
                    break;
                }
            }
        }
        return null;
    }

    /**
     * 获取参数request
     *
     * @param point
     * @return
     */
    private HttpServletRequest getRequest(JoinPoint point) {
        Object[] args = point.getArgs();
        for (Object obj : args) {
            if (obj instanceof HttpServletRequest)
                return (HttpServletRequest) obj;
        }
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        return request;
    }

    /**
     * 获取IP
     * @param request
     * @return
     */
    private String getRequestIP(HttpServletRequest request) {
        String remoteAddr = "";
        if (request != null) {
            remoteAddr = request.getHeader("X-FORWARDED-FOR");
            if (remoteAddr == null || "".equals(remoteAddr)) {
                remoteAddr = request.getRemoteAddr();
            }
        }
        if(StringUtils.equalsIgnoreCase(remoteAddr, "0:0:0:0:0:0:0:1")){
            remoteAddr = "127.0.0.1";
        }
        return remoteAddr;
    }

    private void insertLog(HttpServletRequest request, Log Log) {

        Principal principal = request.getUserPrincipal();

        String ip = this.getRequestIP(request);
        OperationLog sysLog = new OperationLog();
        sysLog.setTime(new Date());
        sysLog.setAccount(principal.getName());
        sysLog.setIp(ip);
        sysLog.setLogtype(Log.openType());
        sysLog.setLogdesc(Log.remark());
        String logDesc = (String)request.getAttribute("log");
        if(StringUtils.isNotBlank(logDesc)){
            sysLog.setLogdesc(logDesc);
        }
        operLogMapper.addOperLog(sysLog);
        System.out.println(sysLog);
    }
}
